import json
from os.path import join

import pygame, sys, time, copy
from pygame import surface, color, SurfaceType
from pygame.draw import rect
from pygame.locals import *

from ShuduSprite import CountDownSprite, CellSprite
from count import CountDown

black = (0, 0, 0)
white = (255, 255, 255)
red = (200, 0, 0)
green = (0, 200, 0)
bright_red = (255, 0, 0)
bright_green = (0, 255, 0)
grey = (88, 88, 88)
mWhite = (255, 251, 240)
blue = (0, 0, 255)


class Shudu:
    running = True
    title = "数独游戏"
    # 控制退出
    fontFamily = "comicsansms"
    # 默认字体
    difficulty = 1  # 难度控制，三个难度：简单1 普通2 困难3
    level = 1  # 关卡控制，1-10关
    isPaused = False  # 暂停模式
    isAnswer = False  # 答案模式
    errorCount = 0  # 错误次数
    recordFile = "record.json"  # 记录文件
    score = -1  # 得分
    actions = []
    time = 0
    is_game_over = False

    def __init__(self):
        self.countDown = None
        self.draw = None
        pygame.init()
        pygame.font.init()
        self.clock = pygame.time.Clock()
        display_size = self.display_width, self.display_height = 800, 600  # 设置窗口大小
        self.gameScreen = pygame.display.set_mode(display_size)
        pygame.display.set_caption(self.title)
        self.gameScreen.fill(white)
        pygame.display.flip()
        self.timeStart = int(time.time())  # 时间记录器# 其他游戏细节
        # self.timeColor = greyself.pausedText = "Pause"
        self.pausedColor = black  # 数独初始化

    def initSudoku(self):
        self.until = Sudoku()
        self.sodoku = copy.deepcopy(self.until.play)  # 数独数组
        self.game = copy.deepcopy(self.until.play)  # 游戏数组
        self.answer = copy.deepcopy(self.until.board)  # 答案数组
        self.position = (-1, -1)  # 选中位置
        self.errorCursor = (-1, -1)  # 错误指示

    def start(self):  # 游戏运行界面
        self.Index()
        self.clock.tick(60)
        while self.running:
            for event in pygame.event.get():
                # 退出
                if event.type == pygame.QUIT: self.exit()  # 检测输入
                if event.type == USEREVENT:
                    self.rendorCountDown()
                if event.type == pygame.MOUSEBUTTONDOWN:
                    self.position = event.pos
                    for obj in self.actions:
                        if obj['rect'].collidepoint(event.pos):
                            print(obj['name'])
                            if (obj['action_arg'] is not None):
                                obj['action'](obj['action_arg'])
                            else:
                                obj['action']()
                if (event.type == pygame.KEYDOWN):
                    self.handleKeyDown(event)

                # print(event)

    def handleKeyDown(self, event):
        if self.isPaused:
            return

        user_value = -1
        if event.key == 8:
            user_value = 0

        if pygame.K_1 <= event.key <= pygame.K_9:
            user_value = int(event.unicode)

        if (user_value < 0):
            return

        mousePositon = pygame.mouse.get_pos()
        self.is_game_over = True
        for sprite in self.cellGroup:
            if not sprite.shuduCell.is_edit:
                continue
            if (sprite.rect.collidepoint(mousePositon)):
                i = sprite.shuduCell.i
                j = sprite.shuduCell.j
                self.sodoku[i][j].set_user_value(user_value)
                sprite.shuduCell.set_user_value(user_value)
                print("第%d行第%d列输入数字:%d,是否正确 %d" % (j+1, i+1, user_value,self.sodoku[i][j].isRight()))
                self.renderPlayOrAnswer(1)
            if not sprite.shuduCell.isRight():
                self.is_game_over = False
        # 游戏结束
        if self.is_game_over:
            self.gameSuccess()

    def gameSuccess(self):
        self.pause()
        text = "恭喜您完成游戏,耗时: " + str(self.countDown.getCount(self.isPaused)) + "秒!"
        self.fontRender(text, red, 30,
                        (235, 520))
        print(text)
        pygame.display.flip()

    def exit(self):  # 退出游戏#
        # self.file.close()
        pygame.quit()
        sys.exit()

    def Index(self):  # 绘制主页
        self.clear()
        self.countDown = None

        y = self.display_height / 1.5
        rectSize = self.display_width / 8, self.display_height / 12
        fontSize = 20
        self.fontRender("数独游戏", black, 115,
                        (self.display_width / 2, self.display_height / 3))  # 主页字体
        self.buttonRender("开始", green, bright_green, black, (150, y), rectSize, fontSize,
                          action=self.Difficulty_select)  # 开始按钮
        self.buttonRender("关闭", red, bright_red, black, (550, y), rectSize, fontSize,
                          action=self.exit)  # 关闭按钮
        pygame.display.flip()

    def fontRender(self, text, color, size, position, ttf="simsun.ttf"):  # 字体渲染
        font = pygame.font.Font(ttf, size)
        surf = font.render(text, True, color)
        surfRect = surf.get_rect()
        surfRect.center = position
        self.gameScreen.blit(surf, surfRect)

    def fontRenderSpr(self, text, color, size, position, ttf="simsun.ttf"):  # 字体渲染
        font = pygame.font.Font(ttf, size)
        surf = font.render(text, True, color)
        surfRect = surf.get_rect()
        surfRect.center = position
        self.gameScreen.blit(surf, surfRect)

    def buttonRender(self, text, rectColor, floatingColor, fontColor, position, rectSize, fontSize, ttf="simsun.ttf",
                     border=0, action=None, actionArgs=None, timeDelay=True):
        rects = rect(self.gameScreen, rectColor, (position, rectSize))
        mousePositon = pygame.mouse.get_pos()  # 鼠标位置
        click = pygame.mouse.get_pressed()  # 鼠标按键
        pygame.draw.rect(self.gameScreen, rectColor, (position, rectSize), border)  # 绘制字体
        # if (position[0] + rectSize[0] > mousePositon[0] > position[0]) and (
        #         position[1] + rectSize[1] > mousePositon[1] > position[1]):
        #     if click[0] == 1 and action is not None:
        #         if timeDelay:
        #             time.sleep(0.2)
        #             if actionArgs is not None:
        #                 action(actionArgs)
        #     else:
        #         if action is not None:
        #             action()
        # else:
        #
        fontPosition = position[0] + rectSize[0] / 2, position[1] + rectSize[1] / 2
        self.fontRender(text, fontColor, fontSize, fontPosition, ttf=ttf)
        if action is None:
            return True

        for item in self.actions:
            if item['name'] == text:
                return True

        obj = {"name": text, "action": action, "rect": rects, "action_arg": actionArgs}
        self.actions.append(obj)

    def gameButtons(self):
        rectSize = 70, 30
        fontSize = 15
        y = self.display_height / 1.8
        self.buttonRender("返回首页", green, bright_green, black, (530, 150), rectSize, fontSize,
                          action=self.Index)  # 开始按钮

        self.buttonRender("暂停", green, bright_green, black, (620, 150), rectSize, fontSize,
                          action=self.pause)

        self.buttonRender("继续", green, bright_green, black, (700, 150), rectSize, fontSize,
                          action=self.unpause)
        self.buttonRender("刷新", green, bright_green, black, (530, 200), rectSize, fontSize,
                          action=self.Difficulty_select)  # 开始按钮
        self.buttonRender("答案", green, bright_green, black, (620, 200), rectSize, fontSize,
                          action=self.renderPlayOrAnswer, actionArgs=2)
        self.buttonRender("还原", green, bright_green, black, (700, 200), rectSize, fontSize,
                          action=self.renderPlayOrAnswer, actionArgs=1)
        self.buttonRender("重置游戏", green, bright_green, black, (530, 250), rectSize, fontSize,
                          action=self.resetGame)  # 开始按钮

    def resetGame(self):
        self.sodoku = copy.deepcopy(self.game)
        self.renderPlayOrAnswer(1)
    def Difficulty_select(self):
        # messagebox.showinfo("提示", "选择难度")
        self.clear()
        self.initSudoku()
        self.gameButtons()

        y = 30
        x = 50
        for step in range(1, 11):
            pygame.draw.aaline(self.gameScreen, black, (47, y - 3), (497, y - 3))
            pygame.draw.aaline(self.gameScreen, black, (x - 3, 28), (x - 3, 477))
            y += 50
            x += 50

        self.unpause()
        self.countDown = CountDown()
        self.rendorCountDown()
        pygame.time.set_timer(USEREVENT, 1000, 0)

        self.cellGroup = None
        self.renderPlayOrAnswer(1)
        pygame.display.flip()

    def renderPlayOrAnswer(self, type=1):
        # messagebox.showinfo("提示", "选择难度")
        if self.cellGroup != None:
            self.cellGroup.remove(self.cellGroup.sprites())

        self.cellGroup = pygame.sprite.Group()
        if type == 1:
            arr = copy.deepcopy(self.sodoku)
            self.unpause()
        elif type == 2:
            arr = copy.deepcopy(self.answer)
            self.pause()

        x = 50
        for step in range(9):
            y = 30
            for step2 in range(9):
                self.cellGroup.add(CellSprite(x, y, arr[step][step2]))
                y += 50
            x += 50
        self.cellGroup.draw(self.gameScreen)

        pygame.display.flip()

    def rendorCountDown(self):
        if (self.countDown):
            my_group = pygame.sprite.Group()
            my_group.add(CountDownSprite(610, 30, self.countDown.getCount(self.isPause())))
            my_group.draw(self.gameScreen)
            pygame.display.flip()

    def clear(self):
        self.gameScreen.fill(white)
        self.actions = []
        pygame.display.flip()

    def isPause(self):
        if self.is_game_over:
            return 1

        return self.isPaused

    def pause(self):

        if self.is_game_over:
            return

        self.isPaused = 1

    def unpause(self):
        if self.is_game_over:
            return

        self.isPaused = 0


class Sudoku:

    def __init__(self):

        # 初始化数独游戏的初始状态

        base = 3

        side = base * base

        # pattern for a baseline valid solution
        def pattern(r, c):
            return (base * (r % base) + r // base + c) % side

        # randomize rows, columns and numbers (of valid base pattern)
        from random import sample
        def shuffle(s):
            return sample(s, len(s))

        rBase = range(base)
        rows = [g * base + r for g in shuffle(rBase) for r in shuffle(rBase)]
        cols = [g * base + c for g in shuffle(rBase) for c in shuffle(rBase)]
        nums = shuffle(range(1, base * base + 1))

        # produce board using randomized baseline pattern
        self.board = [[nums[pattern(r, c)] for c in cols] for r in rows]
        for i in range(9):
            print(self.board[i])
        for i in range(9):
            for j in range(9):
                self.board[i][j] = ShuduCell(self.board[i][j], 0, i, j)


        self.play = copy.deepcopy(self.board)
        squares = side * side
        empties = squares // 8
        for p in sample(range(squares), empties):
            self.play[p // side][p % side].cell_value = 0
            self.play[p // side][p % side].is_edit = 1

        # self.solve()

    def print_board(self):

        # 打印数独游戏的当前状态

        print(self.play)

        print(self.board)

    def valid(self, row, col, num):

        # 验证数独游戏的当前状态是否合法

        for i in range(9):

            if self.board[row][i] == num:
                return False

            if self.board[i][col] == num:
                return False

            if self.board[3 * (row // 3) + i // 3][3 * (col // 3) + i % 3] == num:
                return False

        return True

    def solve(self):

        # 使用回溯法求解数独游戏

        for i in range(9):

            for j in range(9):

                if self.board[i][j] == 0:

                    for num in range(1, 10):

                        if self.valid(i, j, num):

                            self.board[i][j] = num

                            if self.solve():
                                return True

                            self.board[i][j] = 0

                    return False

        return True

    def board(self):
        return self.board

    def play(self):
        return self.play


class ShuduCell:
    is_edit = 0
    value = 0
    user_value = 0
    is_answer = 0
    cell_value = 0

    def __init__(self, value, is_edit, i, j):
        self.value = value
        self.is_edit = is_edit
        self.cell_value = value
        self.i = i
        self.j = j

    def set_user_value(self, user_value):
        if self.is_edit == 0:
            return

        self.user_value = user_value
        self.cell_value = user_value
        if user_value != self.value:
            self.is_answer = 0
        else:
            self.is_answer = 1

    def isRight(self):
        if self.is_edit == 0:
            return True

        if self.is_answer == 1:
            return True

        return False
